package com.yn.sample.execution.executor;

import com.yn.sample.domain.ConstantPoolItem;
import com.yn.sample.domain.ConstantPoolItemTypeEnum;
import com.yn.sample.domain.InstructionExecutionResult;
import com.yn.sample.execution.InstructionExecutionContext;
import com.yn.sample.util.OpCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Objects;

@Component
@Slf4j
public class ExecutorForInvokeSpecial implements ExecutorByOpCode{

    @Override
    public String getOpCode() {
        return OpCodeEnum.invokespecial.name();
    }

    @Override
    public InstructionExecutionResult execute(InstructionExecutionContext context) {
        /**
         * 获取操作数，操作数是常量池的符号引用；比如
         *  16: invokespecial #4                  // Method java/lang/IllegalArgumentException."<init>":()V
         *  其中，#2在常量池中：
         *  #4 = Methodref          #3.#26         // java/lang/IllegalArgumentException."<init>":()V
         */
        String operand = context.getInstructionVO().getOperand();
        /**
         * 根据operand，查找常量池，找到对应的符号引用
         */
        ConstantPoolItem poolItem = context.getConstantPoolItems().stream().filter(constantPoolItem -> Objects.equals(constantPoolItem.getId(), operand))
                .findFirst().orElse(null);
        if (poolItem == null) {
            throw new RuntimeException();
        }

        boolean b = Objects.equals(poolItem.getConstantPoolItemTypeEnum(), ConstantPoolItemTypeEnum.Methodref);
        if (!b) {
            throw new RuntimeException();
        }

        /**
         * 一般comment就是这一段内容：
         * java/lang/IllegalArgumentException."<init>":()V
         */
        String comment = poolItem.getComment();
        if (comment.contains("<init>")) {
            /**
             * 如果是初始化方法,因为我们这边模拟的话，在new指令中，已经执行过init了，我们这里不处理了，直接将栈顶引用出栈
             */
            context.getOperandStack().removeLast();
            return null;
        }

        // 剩余的情形，todo:

        return null;
    }
}
